/**
 * weapp-js v1.7.1(2021-4-16)
 * https://codeup.aliyun.com/motigo/motigo/weapp_base
 * Copyright@ 2021 Motigo, Inc.
 * 
 */
import BaseRequest from './base_request.js';
import request from './request.js';
import ui from './ui.js';

const USER_KEYS = [
    'openid', 'unionid', 'nickname', 'avatar',
    'gender', 'country', 'city', 'province',
    'language',
];

export default {
    id: '', // session_id: wapp_base自定义的id
    appid: '',
    user: {
        openid: null,
        unionid: null,
        nickname: null,
        avatar: null,
        gender: null,
        country: null,
        city: null,
        province: null,
        language: null
    },
    __ready: false,
    /* 初始化，在app的onLaunch里面调用 */
    init(appid, login) {
        this.appid = appid;
        this._clearUser();
        this._getSessionCache(false).catch(()=>{});

        return new Promise((resolve, reject) => {
            if (login) {
                this._sessionLogin().then(data => {
                    this.__ready = true;
                    resolve(data);
                }, err => {
                    reject(err);
                })
            } else {
                this.__ready = true;
                resolve();
            }
        });
    },
    /* 检查是否ready */
    check() {
        return new Promise(resolve => {
            if (this.__ready) {
                resolve();
            } else {
                let start = Date.now();
                let timer = setInterval(() => {
                    if (this.__ready || (Date.now() - start) > 5 * 1000) {
                        clearInterval(timer);
                        resolve();
                    }
                }, 50);
            }
        });
    },
    isDef(obj) {
        return obj !== undefined && obj !== null;
    },
    // 能够获取nickname、avatar、gender等信息的登录接口，如果绑定了开放平台，也可以获取到unionid
    login(opts) {
        return new Promise((resolve, reject) => {
            this._sessionLogin(true).then(() => {
                if ( this.isDef(this.user.openid) && this.isDef(this.user.nickname)) {
                    resolve(this.user);
                } else {
                    ui.login(opts).then(resolve, err=>{
                        this._clearSessionCache();
                        reject(err);
                    });
                }
            }, err => {
                err;
                reject({
                    errCode: '',
                    errMsg: 'session login fail'
                });
            });
        });
    },
    decrpytUserInfo(encryptData, iv) {
        return new Promise((resolve, reject) => {
            if (this.appid && encryptData && iv) {
                BaseRequest.post('/user/decrypt/' + this.appid, {
                    encrypted_data: encryptData,
                    iv: iv
                }).then(data => {
                    data.session_id = this.id;
                    const session_data = {
                        session_id: this.id,
                        openid: data.openId,
                        unionid: data.unionId,
                        nickname: data.nickName,
                        gender: data.gender,
                        avatar: data.avatarUrl,
                        country: data.country,
                        city: data.city,
                        province: data.province,
                        language: data.language
                    };
                    this._setSessionCache(session_data);
                    resolve(session_data);
                }, err => {
                    console.error('decrypt user info fail, err:', err);
                    if (err && err.ret == -3) { // invalid session
                        this._clearSessionCache();
                    }
                    reject(err ? (err.msg) : '');
                });
            } else {
                reject('invalid param');
            }
        })
    },
    decrpytUserPhone(encrypt_data, iv) {
        return new Promise((resolve, reject) => {
            if (this.appid && encrypt_data && iv) {
                BaseRequest.post('/phone/decrypt/' + this.appid, {
                    encrypted_data: encrypt_data,
                    iv: iv
                }).then(data => {
                    data.session_id = this.id;
                    const session_data = {
                        user_phone: data.phoneNumber,
                        pure_phone: data.purePhoneNumber,
                        country_code: data.countryCode
                    }
                    resolve(session_data);
                }, err => {
                    console.error('decrypt user phone fail, err:', err);
                    if (err && err.ret == -3) { // invalid session
                        this._clearSessionCache();
                    }
                    reject(err ? (err.msg) : '');
                });
            } else {
                reject('invalid param');
            }
        })
    },
    // 登录，会检查session的有效性，无效则使用wx.login登录并从weapp_base中获得openid/unionid等信息
    _sessionLogin(hard_mode) {
        return new Promise((resolve, reject) => {
            this._checkSession(hard_mode).then((data) => {
                resolve(data);
            }, () => {
                this._clearUser();
                wx.login({
                    timeout: 3000,
                    success: res => {
                        BaseRequest.post('/auth/session/' + this.appid, {
                            code: res.code
                        }).then(data => {
                            this._setSessionCache(data);
                            resolve(data);
                        }, err => {
                            console.error('base_request fail, err:', err)
                            reject(err);
                        });
                    },
                    fail(res) {
                        console.error('wx.login fail! err:', res);
                        reject(res);
                    }
                });
            });
        });
    },
    _checkSession(hard_mode) {
        return new Promise((resolve, reject) => {
            wx.checkSession({
                success: () => {
                    this._getSessionCache(hard_mode).then(data => {
                        resolve(data);
                    }, err => {
                        err;
                        reject();
                    });
                },
                fail:()=>{
                    reject();
                }
            });
        });
    },
    _getSessionCache(hard_mode) {
        hard_mode = hard_mode == undefined ? false : hard_mode;

        return new Promise((resolve, reject) => {
            wx.getStorage({
                key: '__session__',
                success: res => {
                    try {
                        const sessionData = JSON.parse(res.data);
                        sessionData.create_time = sessionData.create_time || 1;
                        let ttl = hard_mode ? 2 * 60 : 24 * 3600; // hard模式session过期时间2分钟

                        // 本地缓存的信息，2.5天过期
                        if (Date.now() / 1000.0 - sessionData.create_time < ttl) {
                            if(this.isDef(sessionData.session_id) && this.isDef(sessionData.openid)) {
                                console.log('use cache');
                                this.id = sessionData.session_id;
                                this.__updateUserData(sessionData);
                                resolve(sessionData);
                            } else {
                                reject();
                            }
                        } else {
                            reject();
                        }
                    } catch (e) {
                        e;
                        reject();
                    }
                },
                fail:()=>{
                    reject();
                }
            })
        })
    },
    _setSessionCache(sessionData) {
        if (sessionData) {
            if(sessionData.session_id) {
                this.id = sessionData.session_id;
            }

            sessionData.unionid = sessionData.unionid || this.user.unionid;
            sessionData.openid = sessionData.openid || this.user.openid;
            sessionData.session_id = sessionData.session_id || this.id;

            sessionData.create_time = parseInt(Date.now() / 1000.0);
            wx.setStorage({
                key: '__session__',
                data: JSON.stringify(sessionData),
            });

            this.__updateUserData(sessionData);
        }
    },
    _clearSessionCache() {
        wx.removeStorage({
            key: '__session__'
        })
    },
    _clearUser() {
        for (let k in this.user) {
            this.user[k] = null;
        }
    },
    __updateUserData(sessionData) {
        USER_KEYS.forEach(k => {
            if (k in sessionData) {
                this.user[k] = sessionData[k];
            }
        });

        BaseRequest._update_session(
            this.id, this.appid, this.user.openid, this.user.unionid
        );
        request._update_session(
            this.id, this.appid, this.user.openid, this.user.unionid
        );
    }
}